Breast cancer example
- part of study https://doi.org/10.1093/jnci/djj052)
- Histologic grade in breast cancer clinically prognostic. Association of histologic grade on expression of KPNA2 gene that is known to be associated with poor BC prognosis.
- Population: all current and future breast cancer patients






Data Exploration
Import
library(tidyverse)
gene <- read.table("https://raw.githubusercontent.com/statOmics/SGA2020/data/gse2990BreastcancerOneGene.txt",header=TRUE)
head(gene)
## sample_name grade node size age gene
## 28 OXFT_2221 3 1 5.5 76 367.8179
## 29 OXFT_209 3 1 2.5 66 590.3576
## 30 OXFT_1769 1 1 3.5 86 346.6583
## 31 OXFT_928 1 0 1.1 47 118.6996
## 32 OXFT_2093 1 1 2.2 74 519.4489
## 33 OXFT_1770 1 1 1.7 69 258.4455
We will transform the variable grade and node to a factor
gene$grade <- as.factor(gene$grade)
gene$node <- as.factor(gene$node)
Summary statistics
geneSum <- gene %>%
group_by(grade) %>%
summarize(mean = mean(gene),
sd = sd(gene),
n=length(gene)
) %>%
mutate(se = sd/sqrt(n))
geneSum
## # A tibble: 2 x 5
## grade mean sd n se
## <fct> <dbl> <dbl> <int> <dbl>
## 1 1 264. 117. 19 26.7
## 2 3 606. 267. 17 64.9
Visualisation
gene %>%
ggplot(aes(x=grade,y=gene)) +
geom_boxplot(outlier.shape=NA) +
geom_point()

We can also save the plots as objects for later use!
p1 <- gene %>%
ggplot(aes(x=grade,y=gene)) +
geom_boxplot(outlier.shape=NA) +
geom_point()
p2 <- gene %>%
filter(grade==1) %>%
ggplot(aes(sample=gene)) +
geom_qq() +
geom_qq_line()
p3 <- gene %>%
filter(grade==1) %>%
ggplot(aes(sample=gene)) +
geom_qq() +
geom_qq_line()
p1



Research questions
Researchers want to assess the association of the histolical grade on KPNA2 gene expression

Estimation of effect size and standard error
effectSize <- tibble(
delta = geneSum$mean[2]- geneSum$mean[1],
seDelta = geneSum %>%
pull(se) %>%
.^2 %>%
sum %>%
sqrt
)
effectSize
## # A tibble: 1 x 2
## delta seDelta
## <dbl> <dbl>
## 1 342. 70.2
Statistical Inference
- Researchers want to assess the association of histological grade on KPNA2 gene expression
- Inference?

- Researchers want to assess the association of histological grade on KPNA2 gene expression
- Inference?
- testing + CI $ $ Assumptions
In general we start from alternative hypothese \(H_A\): we want to show an association
Gene expression of grade 1 and grade 3 patients is on average different
But, we will assess it by falsifying the opposite:
The average KPNA2 gene expression of grade 1 and grade 3 patients is equal
How likely is it to observe an equal or more extreme association than the one observed in the sample when the null hypothesis is true?
When we make assumptions about the distribution of our test statistic we can quantify this probability: p-value.
If the p-value is below a significance threshold \(\alpha\) we reject the null hypothesis
We control the probability on a false positive result at the \(\alpha\)-level (type I error)
- The p-value will only be calculated correctly if the underlying assumptions hold!

grid.arrange(p2,p3,ncol=2)

t.test(gene~grade,data=gene)
##
## Welch Two Sample t-test
##
## data: gene by grade
## t = -4.8806, df = 21.352, p-value = 7.61e-05
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -488.1734 -196.6587
## sample estimates:
## mean in group 1 mean in group 3
## 263.5516 605.9677
effectSize <- effectSize %>%
mutate(t.stat=delta/seDelta) %>%
mutate(p.value= pt(-abs(t.stat),21.352)*2)
effectSize
## # A tibble: 1 x 4
## delta seDelta t.stat p.value
## <dbl> <dbl> <dbl> <dbl>
## 1 342. 70.2 4.88 0.0000761
- Intensities are often not normally distributed and have a mean variance relation
- Commonly log2-transformed
- Differences on log scale:
\[
\log_2(B) - \log_2(A) = \log_2 \frac{B}{A} = \log_2 FC_{\frac{B}{A}}
\]

Conclusion
There is a extremely significant association of the histological grade on the gene expression in tumor tissue. On average, the gene expression for the grade 3 patients is 2.3221304 times higher than the gene expression in grade 1 patients (95% CI [1.75, 3.08], \(p<<0.001\)).


The patients also differ in the their lymph node status. Hence, we have a two factorial design: grade x lymph node status!!!
Solution??

General Linear Model
How can we integrate multiple factors and continuous covariates in linear model.
\[
y_i= \beta_0 + \beta_1 x_{i,1} + \beta_2 x_{i,2} + \beta_{12}x_{i,1}x_{i,2}+\epsilon_i,
\] with
- \(x_{i,1}\) a dummy variable for histological grade: \(x_{i,1}=\begin{cases} 0& \text{grade 1}\\ 1& \text{grade 3} \end{cases}\)
- \(x_{i,2}\) a dummy variable for : \(x_{i,2}=\begin{cases} 0& \text{lymph nodes were not removed}\\ 1& \text{lymph nodes were removed} \end{cases}\)
- \(\epsilon_i\)?
Implementation in R
lm1 <- lm(gene~grade*node,data=gene)
summary(lm1)
##
## Call:
## lm(formula = gene ~ grade * node, data = gene)
##
## Residuals:
## Min 1Q Median 3Q Max
## -356.85 -91.98 -31.47 53.00 612.73
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 207.60 60.00 3.460 0.00155 **
## grade3 434.21 84.85 5.117 1.41e-05 ***
## node1 132.88 92.46 1.437 0.16040
## grade3:node1 -234.43 136.92 -1.712 0.09655 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 199 on 32 degrees of freedom
## Multiple R-squared: 0.4809, Adjusted R-squared: 0.4322
## F-statistic: 9.881 on 3 and 32 DF, p-value: 9.181e-05
Breast cancer example
- Paper: https://doi.org/10.1093/jnci/djj052
- Histologic grade in breast cancer provides clinically important prognostic information. Two factors have to be concidered: Histologic grade (grade 1 and grade 3) and lymph node status (0 vs 1). The researchers assessed gene expression of the KPNA2 gene a protein-coding gene associated with breast cancer and are mainly interested in the association of histological grade. Note, that the gene variable consists of background corrected normalized intensities obtained with a microarray platform. Upon log-transformation, they are known to be a good proxy for the \(\log\) transformed concentration of gene expression product of the KPNA2 gene.
- Research questions and translate them towards model parameters (contrasts)?
- Make an R markdown file to answer the research questions
library(ExploreModelMatrix)
explMx <- VisualizeDesign(gene,designFormula = ~grade*node)
explMx$plotlist
## [[1]]

You can also explore the model matrix interactively:
ExploreModelMatrix(gene,designFormula = ~grade*node)
LS0tCnRpdGxlOiAiUmVjYXAgZ2VuZXJhbCBsaW5lYXIgbW9kZWwiCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IgpkYXRlOiAic3RhdE9taWNzLCBHaGVudCBVbml2ZXJzaXR5IChodHRwczovL3N0YXRvbWljcy5naXRodWIuaW8pIgpvdXRwdXQ6CiAgICBodG1sX2RvY3VtZW50OgogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICB0b2M6IHRydWUKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKCiMgQnJlYXN0IGNhbmNlciBleGFtcGxlCgotIHBhcnQgb2Ygc3R1ZHkgaHR0cHM6Ly9kb2kub3JnLzEwLjEwOTMvam5jaS9kamowNTIpCi0gSGlzdG9sb2dpYyBncmFkZSBpbiBicmVhc3QgY2FuY2VyIGNsaW5pY2FsbHkgcHJvZ25vc3RpYy4KQXNzb2NpYXRpb24gb2YgaGlzdG9sb2dpYyBncmFkZSBvbiBleHByZXNzaW9uIG9mIEtQTkEyIGdlbmUgdGhhdCBpcyBrbm93biB0byBiZSBhc3NvY2lhdGVkIHdpdGggcG9vciBCQyBwcm9nbm9zaXMuCi0gUG9wdWxhdGlvbjogYWxsIGN1cnJlbnQgYW5kIGZ1dHVyZSBicmVhc3QgY2FuY2VyIHBhdGllbnRzCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRPbWljcy9TR0EyMDIwL2RhdGEvZmlncy9zdGF0R2Vub21pY3NHZW50MjAxNzE4LTEuanBlZykKCi0tLQoKIVtdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3MvU0dBMjAyMC9kYXRhL2ZpZ3Mvc3RhdEdlbm9taWNzR2VudDIwMTcxOC0yLmpwZWcpCgotLS0KCiFbXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL1NHQTIwMjAvZGF0YS9maWdzL3N0YXRHZW5vbWljc0dlbnQyMDE3MTgtMy5qcGVnKQoKLS0tCgoKIVtdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3MvU0dBMjAyMC9kYXRhL2ZpZ3Mvc3RhdEdlbm9taWNzR2VudDIwMTcxOC00LmpwZWcpCgotLS0KCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRPbWljcy9TR0EyMDIwL2RhdGEvZmlncy9zdGF0R2Vub21pY3NHZW50MjAxNzE4LTUuanBlZykKCi0tLQoKCiFbXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL1NHQTIwMjAvZGF0YS9maWdzL3N0YXRHZW5vbWljc0dlbnQyMDE3MTgtNi5qcGVnKQoKLS0tCgojIERhdGEgRXhwbG9yYXRpb24KCiMjIEltcG9ydAoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpnZW5lIDwtIHJlYWQudGFibGUoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3MvU0dBMjAyMC9kYXRhL2dzZTI5OTBCcmVhc3RjYW5jZXJPbmVHZW5lLnR4dCIsaGVhZGVyPVRSVUUpCmhlYWQoZ2VuZSkKYGBgCgpXZSB3aWxsIHRyYW5zZm9ybSB0aGUgdmFyaWFibGUgZ3JhZGUgYW5kIG5vZGUgdG8gYSBmYWN0b3IKCmBgYHtyfQpnZW5lJGdyYWRlIDwtIGFzLmZhY3RvcihnZW5lJGdyYWRlKQpnZW5lJG5vZGUgPC0gYXMuZmFjdG9yKGdlbmUkbm9kZSkKYGBgCgojIyBTdW1tYXJ5IHN0YXRpc3RpY3MKCmBgYHtyfQpnZW5lU3VtIDwtIGdlbmUgJT4lCiAgZ3JvdXBfYnkoZ3JhZGUpICU+JQogIHN1bW1hcml6ZShtZWFuID0gbWVhbihnZW5lKSwKICAgICAgICAgICAgc2QgPSBzZChnZW5lKSwKICAgICAgICAgICAgbj1sZW5ndGgoZ2VuZSkKICAgICAgICAgICAgKSAlPiUKICBtdXRhdGUoc2UgPSBzZC9zcXJ0KG4pKQpnZW5lU3VtCmBgYAoKIyMgVmlzdWFsaXNhdGlvbgoKYGBge3J9CmdlbmUgJT4lCiAgZ2dwbG90KGFlcyh4PWdyYWRlLHk9Z2VuZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCldlIGNhbiBhbHNvIHNhdmUgdGhlIHBsb3RzIGFzIG9iamVjdHMgZm9yIGxhdGVyIHVzZSEKCmBgYHtyfQpwMSA8LSBnZW5lICU+JQogIGdncGxvdChhZXMoeD1ncmFkZSx5PWdlbmUpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGU9TkEpICsKICBnZW9tX3BvaW50KCkKCnAyIDwtIGdlbmUgJT4lCiAgZmlsdGVyKGdyYWRlPT0xKSAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZT1nZW5lKSkgKwogIGdlb21fcXEoKSArCiAgZ2VvbV9xcV9saW5lKCkKCnAzIDwtIGdlbmUgJT4lCiAgZmlsdGVyKGdyYWRlPT0xKSAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZT1nZW5lKSkgKwogIGdlb21fcXEoKSArCiAgZ2VvbV9xcV9saW5lKCkKCnAxCnAyCnAzCmBgYAoKCiMjIFJlc2VhcmNoIHF1ZXN0aW9ucwoKUmVzZWFyY2hlcnMgd2FudCB0byBhc3Nlc3MgdGhlIGFzc29jaWF0aW9uIG9mIHRoZSBoaXN0b2xpY2FsIGdyYWRlIG9uIEtQTkEyIGdlbmUgZXhwcmVzc2lvbgoKCgoKIVtdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3MvU0dBMjAyMC9kYXRhL2ZpZ3Mvc3RhdEdlbm9taWNzR2VudDIwMTcxOC02LmpwZWcpCgotLS0KCiMjIEVzdGltYXRpb24gb2YgZWZmZWN0IHNpemUgYW5kIHN0YW5kYXJkIGVycm9yCgpgYGB7cn0KZWZmZWN0U2l6ZSA8LSB0aWJibGUoCiAgZGVsdGEgPSBnZW5lU3VtJG1lYW5bMl0tIGdlbmVTdW0kbWVhblsxXSwKICBzZURlbHRhID0gZ2VuZVN1bSAlPiUKICAgIHB1bGwoc2UpICU+JQogICAgLl4yICU+JQogICAgc3VtICU+JQogICAgc3FydAogICkKZWZmZWN0U2l6ZQpgYGAKCiMgU3RhdGlzdGljYWwgSW5mZXJlbmNlCgotIFJlc2VhcmNoZXJzIHdhbnQgdG8gYXNzZXNzIHRoZSBhc3NvY2lhdGlvbiBvZiBoaXN0b2xvZ2ljYWwgZ3JhZGUgb24gS1BOQTIgZ2VuZSBleHByZXNzaW9uCi0gSW5mZXJlbmNlPwoKLS0tCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRPbWljcy9TR0EyMDIwL2RhdGEvZmlncy9zdGF0R2Vub21pY3NHZW50MjAxNzE4LTcuanBlZykKCi0tLQoKCi0gUmVzZWFyY2hlcnMgd2FudCB0byBhc3Nlc3MgdGhlIGFzc29jaWF0aW9uIG9mIGhpc3RvbG9naWNhbCBncmFkZSBvbiBLUE5BMiBnZW5lIGV4cHJlc3Npb24KLSBJbmZlcmVuY2U/Ci0gdGVzdGluZyArIENJICQgXHJpZ2h0YXJyb3cgJCBBc3N1bXB0aW9ucwoKLS0tCgotIEluIGdlbmVyYWwgd2Ugc3RhcnQgZnJvbSAqKmFsdGVybmF0aXZlIGh5cG90aGVzZSoqICRIX0EkOiB3ZSB3YW50IHRvIHNob3cgYW4gYXNzb2NpYXRpb24KLSBHZW5lIGV4cHJlc3Npb24gb2YgZ3JhZGUgMSBhbmQgZ3JhZGUgMyBwYXRpZW50cyBpcyBvbiBhdmVyYWdlIGRpZmZlcmVudAoKLSBCdXQsIHdlIHdpbGwgYXNzZXNzIGl0IGJ5IGZhbHNpZnlpbmcgdGhlIG9wcG9zaXRlOgoKLSBUaGUgYXZlcmFnZSBLUE5BMiBnZW5lIGV4cHJlc3Npb24gb2YgIGdyYWRlIDEgYW5kIGdyYWRlIDMgcGF0aWVudHMgaXMgZXF1YWwKCi0tLQoKLSBIb3cgbGlrZWx5IGlzIGl0IHRvIG9ic2VydmUgYW4gZXF1YWwgb3IgbW9yZSBleHRyZW1lIGFzc29jaWF0aW9uIHRoYW4gdGhlIG9uZSBvYnNlcnZlZCBpbiB0aGUgc2FtcGxlIHdoZW4gdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0cnVlPwoKLSBXaGVuIHdlIG1ha2UgYXNzdW1wdGlvbnMgYWJvdXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBvdXIgdGVzdCBzdGF0aXN0aWMgd2UgY2FuIHF1YW50aWZ5IHRoaXMgcHJvYmFiaWxpdHk6ICoqcC12YWx1ZSoqLgotIElmIHRoZSBwLXZhbHVlIGlzIGJlbG93IGEgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCAkXGFscGhhJCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcwoKKldlIGNvbnRyb2wgdGhlIHByb2JhYmlsaXR5IG9uIGEgZmFsc2UgcG9zaXRpdmUgcmVzdWx0IGF0IHRoZSAkXGFscGhhJC1sZXZlbCAodHlwZSBJIGVycm9yKSoKCi0gVGhlIHAtdmFsdWUgd2lsbCBvbmx5IGJlIGNhbGN1bGF0ZWQgY29ycmVjdGx5IGlmIHRoZSB1bmRlcmx5aW5nIGFzc3VtcHRpb25zIGhvbGQhCgpgYGB7cn0KbGlicmFyeShncmlkRXh0cmEpCnAxCmdyaWQuYXJyYW5nZShwMixwMyxuY29sPTIpCmBgYAoKYGBge3J9CnQudGVzdChnZW5lfmdyYWRlLGRhdGE9Z2VuZSkKCmVmZmVjdFNpemUgPC0gZWZmZWN0U2l6ZSAlPiUKICBtdXRhdGUodC5zdGF0PWRlbHRhL3NlRGVsdGEpICU+JQogIG11dGF0ZShwLnZhbHVlPSBwdCgtYWJzKHQuc3RhdCksMjEuMzUyKSoyKQoKZWZmZWN0U2l6ZQpgYGAKCi0gSW50ZW5zaXRpZXMgYXJlIG9mdGVuIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCBhbmQgaGF2ZSBhIG1lYW4gdmFyaWFuY2UgcmVsYXRpb24KLSBDb21tb25seSBsb2cyLXRyYW5zZm9ybWVkCi0gRGlmZmVyZW5jZXMgb24gbG9nIHNjYWxlOgoKJCQKXGxvZ18yKEIpIC0gXGxvZ18yKEEpID0gXGxvZ18yIFxmcmFje0J9e0F9ID0gXGxvZ18yIEZDX3tcZnJhY3tCfXtBfX0KJCQKCgoKIVtdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3MvU0dBMjAyMC9kYXRhL2ZpZ3Mvc3RhdEdlbm9taWNzR2VudDIwMTcxOC04LmpwZWcpCgotLS0KCiMjIExvZyB0cmFuc2Zvcm1hdGlvbgoKYGBge3J9CmdlbmUgPC0gZ2VuZSAlPiUKICBtdXRhdGUobGdlbmUgPSBsb2cyKGdlbmUpKQoKcDEgPC0gZ2VuZSAlPiUKICBnZ3Bsb3QoYWVzKHg9Z3JhZGUseT1sZ2VuZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQoKQoKcDIgPC0gZ2VuZSAlPiUKICBmaWx0ZXIoZ3JhZGU9PTEpICU+JQogIGdncGxvdChhZXMoc2FtcGxlPWxnZW5lKSkgKwogIGdlb21fcXEoKSArCiAgZ2VvbV9xcV9saW5lKCkKCnAzIDwtIGdlbmUgJT4lCiAgZmlsdGVyKGdyYWRlPT0xKSAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZT1sZ2VuZSkpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpCgpwMQpncmlkLmFycmFuZ2UocDIscDMsbmNvbD0yKQoKbG9ndGVzdCA8LSB0LnRlc3QobGdlbmV+Z3JhZGUsZGF0YT1nZW5lKQpsb2d0ZXN0Cgpsb2cyRkMgPC0gbG9ndGVzdCRlc3RpbWF0ZVsyXS1sb2d0ZXN0JGVzdGltYXRlWzFdCmxvZzJGQwpuYW1lcyhsb2cyRkMpIDwtICJnMy1nMSIKMl5sb2cyRkMKYGBgCgojIyBDb25jbHVzaW9uCgpUaGVyZSBpcyBhIGV4dHJlbWVseSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiBvZiB0aGUgaGlzdG9sb2dpY2FsIGdyYWRlIG9uIHRoZSBnZW5lIGV4cHJlc3Npb24gaW4gdHVtb3IgdGlzc3VlLiAgT24gYXZlcmFnZSwgdGhlIGdlbmUgZXhwcmVzc2lvbiBmb3IgdGhlIGdyYWRlIDMgcGF0aWVudHMgaXMgYHIgMl5sb2cyRkNgIHRpbWVzIGhpZ2hlciB0aGFuIHRoZSBnZW5lIGV4cHJlc3Npb24gaW4gZ3JhZGUgMSBwYXRpZW50cyAoOTVcJSBDSSAgW2ByIHBhc3RlKHJvdW5kKDJeLWxvZ3Rlc3QkY29uZi5pbnRbMjoxXSwyKSxjb2xsYXBzZT0iLCAiKWBdLCAkcDw8MC4wMDEkKS4KCgoKCiFbXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL1NHQTIwMjAvZGF0YS9maWdzL3N0YXRHZW5vbWljc0dlbnQyMDE3MTgtMTAuanBlZykKCi0tLQoKCiFbXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL1NHQTIwMjAvZGF0YS9maWdzL3N0YXRHZW5vbWljc0dlbnQyMDE3MTgtMTEuanBlZykKCi0tLQoKVGhlIHBhdGllbnRzIGFsc28gZGlmZmVyIGluIHRoZSB0aGVpciBseW1waCBub2RlIHN0YXR1cy4gSGVuY2UsIHdlIGhhdmUgYSB0d28gZmFjdG9yaWFsIGRlc2lnbjogZ3JhZGUgeCBseW1waCBub2RlIHN0YXR1cyEhIQoKU29sdXRpb24/PwoKIVtdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3MvU0dBMjAyMC9kYXRhL2ZpZ3Mvc3RhdEdlbm9taWNzR2VudDIwMTcxOC0xMi5qcGVnKQoKLS0tCgojIEdlbmVyYWwgTGluZWFyIE1vZGVsCgpIb3cgY2FuIHdlIGludGVncmF0ZSBtdWx0aXBsZSBmYWN0b3JzIGFuZCBjb250aW51b3VzIGNvdmFyaWF0ZXMgaW4gbGluZWFyIG1vZGVsLgoKXFsKeV9pPSBcYmV0YV8wICsgXGJldGFfMSB4X3tpLDF9ICsgXGJldGFfMiB4X3tpLDJ9ICsgXGJldGFfezEyfXhfe2ksMX14X3tpLDJ9K1xlcHNpbG9uX2ksClxdCndpdGgKCi0gJHhfe2ksMX0kIGEgZHVtbXkgdmFyaWFibGUgZm9yIGhpc3RvbG9naWNhbCBncmFkZTogJHhfe2ksMX09XGJlZ2lue2Nhc2VzfQowJiBcdGV4dHtncmFkZSAxfVxcCjEmIFx0ZXh0e2dyYWRlIDN9ClxlbmR7Y2FzZXN9JAotICR4X3tpLDJ9JCBhIGR1bW15IHZhcmlhYmxlIGZvciA6ICR4X3tpLDJ9PVxiZWdpbntjYXNlc30KMCYgXHRleHR7bHltcGggbm9kZXMgd2VyZSBub3QgcmVtb3ZlZH1cXAoxJiBcdGV4dHtseW1waCBub2RlcyB3ZXJlIHJlbW92ZWR9ClxlbmR7Y2FzZXN9JAotICRcZXBzaWxvbl9pJD8KCi0tLQoKIyMgSW1wbGVtZW50YXRpb24gaW4gUgoKYGBge3J9CmxtMSA8LSBsbShnZW5lfmdyYWRlKm5vZGUsZGF0YT1nZW5lKQpzdW1tYXJ5KGxtMSkKYGBgCgotLS0KCiMjIEFzc3VtcHRpb25zCgpgYGB7cn0KcGxvdChsbTEpCmBgYAoKLS0tCgojIyBCcmVhc3QgY2FuY2VyIGV4YW1wbGUKCi0gIFBhcGVyOiBodHRwczovL2RvaS5vcmcvMTAuMTA5My9qbmNpL2RqajA1MgotIEhpc3RvbG9naWMgZ3JhZGUgaW4gYnJlYXN0IGNhbmNlciBwcm92aWRlcyBjbGluaWNhbGx5IGltcG9ydGFudCBwcm9nbm9zdGljIGluZm9ybWF0aW9uLiBUd28gZmFjdG9ycyBoYXZlIHRvIGJlIGNvbmNpZGVyZWQ6IEhpc3RvbG9naWMgZ3JhZGUgKGdyYWRlIDEgYW5kIGdyYWRlIDMpIGFuZCBseW1waCBub2RlIHN0YXR1cyAoMCB2cyAxKS4gVGhlIHJlc2VhcmNoZXJzIGFzc2Vzc2VkIGdlbmUgZXhwcmVzc2lvbiBvZiB0aGUgS1BOQTIgZ2VuZSBhIHByb3RlaW4tY29kaW5nIGdlbmUgYXNzb2NpYXRlZCB3aXRoIGJyZWFzdCBjYW5jZXIgYW5kIGFyZSBtYWlubHkgaW50ZXJlc3RlZCBpbiB0aGUgYXNzb2NpYXRpb24gb2YgaGlzdG9sb2dpY2FsIGdyYWRlLiBOb3RlLCB0aGF0IHRoZSBnZW5lIHZhcmlhYmxlIGNvbnNpc3RzIG9mIGJhY2tncm91bmQgY29ycmVjdGVkIG5vcm1hbGl6ZWQgaW50ZW5zaXRpZXMgb2J0YWluZWQgd2l0aCBhIG1pY3JvYXJyYXkgcGxhdGZvcm0uIFVwb24gbG9nLXRyYW5zZm9ybWF0aW9uLCB0aGV5IGFyZSBrbm93biB0byBiZSBhIGdvb2QgcHJveHkgZm9yIHRoZSAkXGxvZyQgdHJhbnNmb3JtZWQgY29uY2VudHJhdGlvbiBvZiBnZW5lIGV4cHJlc3Npb24gcHJvZHVjdCBvZiB0aGUgS1BOQTIgZ2VuZS4KLSBSZXNlYXJjaCBxdWVzdGlvbnMgYW5kIHRyYW5zbGF0ZSB0aGVtIHRvd2FyZHMgbW9kZWwgcGFyYW1ldGVycyAoY29udHJhc3RzKT8KLSBNYWtlIGFuIFIgbWFya2Rvd24gZmlsZSB0byBhbnN3ZXIgdGhlIHJlc2VhcmNoIHF1ZXN0aW9ucwoKCmBgYHtyfQpsaWJyYXJ5KEV4cGxvcmVNb2RlbE1hdHJpeCkKZXhwbE14IDwtIFZpc3VhbGl6ZURlc2lnbihnZW5lLGRlc2lnbkZvcm11bGEgPSB+Z3JhZGUqbm9kZSkKZXhwbE14JHBsb3RsaXN0CmBgYAoKWW91IGNhbiBhbHNvIGV4cGxvcmUgdGhlIG1vZGVsIG1hdHJpeCBpbnRlcmFjdGl2ZWx5OgoKYGBge3IgZXZhbD1GQUxTRX0KRXhwbG9yZU1vZGVsTWF0cml4KGdlbmUsZGVzaWduRm9ybXVsYSA9IH5ncmFkZSpub2RlKQpgYGAKLS0tCgojIExpbmVhciByZWdyZXNzaW9uIGluIG1hdHJpeCBmb3JtCgojIyBTY2FsYXIgZm9ybQoKLSBDb25zaWRlciBhIHZlY3RvciBvZiBwcmVkaWN0b3JzICRcbWF0aGJme3h9PSh4XzEsXGxkb3RzLHhfcCkkIGFuZAotIGEgcmVhbC12YWx1ZWQgcmVzcG9uc2UgJFkkCi0gdGhlbiB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgY2FuIGJlIHdyaXR0ZW4gYXMKXFsKWT1mKFxtYXRoYmZ7eH0pICtcZXBzaWxvbj1cYmV0YV8wK1xzdW1cbGltaXRzX3tqPTF9XnAgeF9qXGJldGFfaiArIFxlcHNpbG9uClxdCndpdGggaS5pLmQuICRcZXBzaWxvblxzaW0gTigwLFxzaWdtYV4yKSQKCiMjIE1hdHJpeCBmb3JtCgotICRuJCBvYnNlcnZhdGlvbnMgJChcbWF0aGJme3h9XzEseV8xKSBcbGRvdHMgKFxtYXRoYmZ7eH1fbix5X24pJAotIFJlZ3Jlc3Npb24gaW4gbWF0cml4IG5vdGF0aW9uClxbXG1hdGhiZntZfT1cbWF0aGJme1hcYmV0YX0gKyBcbWF0aGJme1xlcHNpbG9ufVxdCndpdGggJFxtYXRoYmZ7WX09XGxlZnRbXGJlZ2lue2FycmF5fXtjfXlfMVxcIFx2ZG90c1xceV9uXGVuZHthcnJheX1ccmlnaHRdJCwKJFxtYXRoYmZ7WH09XGxlZnRbXGJlZ2lue2FycmF5fXtjY2NjfSAxJnhfezExfSZcbGRvdHMmeF97MXB9XFwKXHZkb3RzJlx2ZG90cyYmXHZkb3RzXFwKMSZ4X3tuMX0mXGxkb3RzJnhfe25wfQpcZW5ke2FycmF5fVxyaWdodF0kLAokXG1hdGhiZntcYmV0YX09XGxlZnRbXGJlZ2lue2FycmF5fXtjfVxiZXRhXzBcXCBcdmRvdHNcXCBcYmV0YV9wXGVuZHthcnJheX1ccmlnaHRdJCBhbmQKJFxtYXRoYmZ7XGVwc2lsb259PVxsZWZ0W1xiZWdpbnthcnJheX17Y30gXGVwc2lsb25fMSBcXCBcdmRvdHMgXFwgXGVwc2lsb25fblxlbmR7YXJyYXl9XHJpZ2h0XSQKCiMjIExlYXN0IFNxdWFyZXMgKExTKQotIE1pbmltaXplIHRoZSByZXNpZHVhbCBzdW0gb2Ygc3F1YXJlcwpcYmVnaW57ZXFuYXJyYXkqfQpSU1MoXG1hdGhiZntcYmV0YX0pJj0mXHN1bVxsaW1pdHNfe2k9MX1ebiBlXjJfaVxcCiY9JlxzdW1cbGltaXRzX3tpPTF9Xm4gXGxlZnQoeV9pLVxiZXRhXzAtXHN1bVxsaW1pdHNfe2o9MX1ecCB4X3tpan1cYmV0YV9qXHJpZ2h0KV4yClxlbmR7ZXFuYXJyYXkqfQotIG9yIGluIG1hdHJpeCBub3RhdGlvbgpcYmVnaW57ZXFuYXJyYXkqfQpSU1MoXG1hdGhiZntcYmV0YX0pJj0mKFxtYXRoYmZ7WX0tXG1hdGhiZntYXGJldGF9KV5UKFxtYXRoYmZ7WX0tXG1hdGhiZntYXGJldGF9KVxcCiY9JlxWZXJ0IFxtYXRoYmZ7WX0tXG1hdGhiZntYXGJldGF9XFZlcnReMgpcZW5ke2VxbmFycmF5Kn0Kd2l0aCB0aGUgJExfMiQtbm9ybSBvZiBhICRwJC1kaW0uIHZlY3RvciAkdiQgJFxWZXJ0IFxtYXRoYmZ7dn0gXFZlcnQ9XHNxcnR7dl8xXjIrXGxkb3RzK3ZfcF4yfSQKJFxyaWdodGFycm93JCBcYWxlcnR7JFxoYXR7XG1hdGhiZntcYmV0YX19PVx0ZXh0e2FyZ21pbn1fXGJldGEgXFZlcnQgXG1hdGhiZntZfS1cbWF0aGJme1hcYmV0YX1cVmVydF4yJH0KCi0tLQoKIyMjIE1pbmltaXplIFJTUwpcWwpcYmVnaW57YXJyYXl9e2NjY30KXGZyYWN7XHBhcnRpYWwgUlNTfXtccGFydGlhbCBcbWF0aGJme1xiZXRhfX0mPSZcbWF0aGJmezB9XFxcXApcZnJhY3soXG1hdGhiZntZfS1cbWF0aGJme1hcYmV0YX0pXlQoXG1hdGhiZntZfS1cbWF0aGJme1hcYmV0YX0pfXtccGFydGlhbCBcbWF0aGJme1xiZXRhfX0mPSZcbWF0aGJmezB9XFxcXAotMlxtYXRoYmZ7WH1eVChcbWF0aGJme1l9LVxtYXRoYmZ7WFxiZXRhfSkmPSZcbWF0aGJmezB9XFxcXApcbWF0aGJme1h9XlRcbWF0aGJme1hcYmV0YX0mPSZcbWF0aGJme1h9XlRcbWF0aGJme1l9XFxcXApcaGF0e1xtYXRoYmZ7XGJldGF9fSY9JihcbWF0aGJme1h9XlRcbWF0aGJme1h9KV57LTF9XG1hdGhiZntYfV5UXG1hdGhiZntZfQpcZW5ke2FycmF5fQpcXQoKLS0tCgojIyBWYXJpYW5jZSBFc3RpbWF0b3I/ClxbClxiZWdpbnthcnJheX17Y2NsfQpcaGF0e1xib2xkbWF0aHtcU2lnbWF9fV97XGhhdHtcbWF0aGJme1xiZXRhfX19CiY9Jlx0ZXh0e3Zhcn1cbGVmdFsoXG1hdGhiZntYfV5UXG1hdGhiZntYfSleey0xfVxtYXRoYmZ7WH1eVFxtYXRoYmZ7WX1ccmlnaHRdXFxcXAomPSYoXG1hdGhiZntYfV5UXG1hdGhiZntYfSleey0xfVxtYXRoYmZ7WH1eVFx0ZXh0e3Zhcn1cbGVmdFtcbWF0aGJme1l9XHJpZ2h0XVxtYXRoYmZ7WH0oXG1hdGhiZntYfV5UXG1hdGhiZntYfSleey0xfVxcXFwKJj0mKFxtYXRoYmZ7WH1eVFxtYXRoYmZ7WH0pXnstMX1cbWF0aGJme1h9XlQoXG1hdGhiZntJfVxzaWdtYV4yKVxtYXRoYmZ7WH0oXG1hdGhiZntYfV5UXG1hdGhiZntYfSleey0xfQpcXFxcCiY9JihcbWF0aGJme1h9XlRcbWF0aGJme1h9KV57LTF9XG1hdGhiZntYfV5UXG1hdGhiZntJfVxxdWFkXG1hdGhiZntYfShcbWF0aGJme1h9XlRcbWF0aGJme1h9KV57LTF9XHNpZ21hXjJcXFxcCiVcaGF0e1xib2xkbWF0aHtcU2lnbWF9fV97XGhhdHtcbWF0aGJme1xiZXRhfX19Jj0mKFxtYXRoYmZ7WH1eVFxtYXRoYmZ7WH0pXnstMX1cbWF0aGJme1h9XlRcdmFyXGxlZnRbXG1hdGhiZntZfVxyaWdodF0oXG1hdGhiZntYfV5UXG1hdGhiZntYfSleey0xfVxtYXRoYmZ7WH1cXAomPSYoXG1hdGhiZntYfV5UXG1hdGhiZntYfSleey0xfVxtYXRoYmZ7WH1eVFxtYXRoYmZ7WH0oXG1hdGhiZntYfV5UXG1hdGhiZntYfSleey0xfVxzaWdtYV4yXFxcXAomPSYoXG1hdGhiZntYfV5UXG1hdGhiZntYfSleey0xfVxzaWdtYV4yClxlbmR7YXJyYXl9ClxdCgotLS0KCiMgSG9tZXdvcms6IEFkb3B0IHRoZSBnZW5lIGFuYWx5c2lzIG9uIGxvZyBzY2FsZSBpbiBtYXRyaXggZm9ybSEKCjEuIFN0dWR5IHRoZSBzb2x1dGlvbiBvZiB0aGUgZXhlcmNpc2UgdG8gdW5kZXJzdGFuZCB0aGUgYW5hbHlzaXMgaW4gUgpodHRwczovL2d0cGIuZ2l0aHViLmlvL1BTTFMyMC9wYWdlcy8wOC1tdWx0aXBsZVJlZ3Jlc3Npb24vMDgtbXVsdGlwbGVSZWdyZXNzaW9uX0tQTkEyLmh0bWwKCjIuIENhbGN1bGF0ZQotIG1vZGVsIHBhcmFtZXRlcnMgYW5kIGNvbnRyYXN0cyBvZiBpbnRlcmVzdAotIHN0YW5kYXJkIGVycm9ycywgc3RhbmRhcmQgZXJyb3JzIG9uIGNvbnRyYXN0cwotIHQtdGVzdCBzdGF0aXN0aWNzIG9uIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIGFuZCBjb250cmFzdHMgb2YgaW50ZXJlc3QKCjMuIENvbXBhcmUgeW91ciByZXN1bHRzIHdpdGggdGhlIG91dHB1dCBvZiB0aGUgbG0oLikgZnVuY3Rpb24KCgotLS0KCiMjIEluc3BpcmF0aW9uCgpUaXA6IGRldGFpbHMgb24gdGhlIGltcGxlbWVudGF0aW9uIGNhbiBiZSBmb3VuZCBpbiB0aGUgYm9vayBvZiBGYXJhd2F5IChjaGFwdGVyIDIpLiBodHRwczovL3Blb3BsZS5iYXRoLmFjLnVrL2pqZjIzL2Jvb2svCgotIERlc2lnbiBtYXRyaXgKCmBgYHtyfQpYIDwtIG1vZGVsLm1hdHJpeCh+Z3JhZGUqbm9kZSxkYXRhPWdlbmUpCmBgYAoKLSBUcmFuc3Bvc2Ugb2YgYSBtYXRyaXg6IHVzZSBmdW5jdGlvbiB0KC4pCgpgYGB7cn0KdChYKQpgYGAKCi0gTWF0cml4IHByb2R1Y3QgJVwqJSBvcGVyYXRvcgoKYGBge3J9CnQoWCklKiVYCmBgYAoKLSBEZWdyZWVzIG9mIGZyZWVkb20gb2YgYSBtb2RlbD8KJCQgZGYgPSAgbi1wJAoKYGBge3J9CnN1bW1hcnkobG0xKQpkZlJlcyA8LSAobnJvdyhYKS1uY29sKFgpKQpkZlJlcwpgYGAKCi0gVmFyaWFuY2UgZXN0aW1hdG9yOiBNU0UKCiQkClxoYXQgXHNpZ21hXjIgPSBcc3VtXGxpbWl0c197aT0xfV5uIFxlcHNpbG9uX2leMn17bi1wfQokJAoKCi0gSW52ZXJ0IG1hdHJpeDogdXNlIGZ1bmN0aW9uIHNvbHZlKC4pCgotIERpYWdvbmFsIGVsZW1lbnRzIG9mIGEgbWF0cml4OiB1c2UgZnVuY3Rpb24gZGlhZyguKQoKYGBge3J9CnQoWCklKiVYCmRpYWcodChYKSUqJVgpCmBgYAo=